[Chapter1] - 애플리케이션 준비하기
객체에서 함수로를 공부하며 작성한 글입니다.
혼자 공부하고 정리한 내용이며, 틀린 부분은 지적해주시면 감사드리겠습니다 😀
제타이
할 일 목록 애플리케이션인 제타이, 일본어로 ‘반드시’라는 의미를 가진다. 이 애플리케이션은 린 접근 방법의 관점에서 build-measure-learn 의 루프 형태로 진행할 것이다. 요구 사항을 정의하고, 피드백을 수집한 후, 이전 구현으로부터 교훈을 얻고, 다음을 진행하는 것이다.
A core component of Lean Startup methodology is the build-measure-learn feedback loop. Develop An MVP - theleanstartup
요구 사항
할 일 목록 소프트웨어는 최소한 다음과 같은 일을 할 수 있어야 한다.
- 하나의 할 일 목록을 본다.
- 이름과 설명을 정해서, 새로운 할 일 목록을 생성한다.
- 모든 할 일 목록을 본다.
- 할 일 목록에 할 일을 설명과 함께 추가할 수 있다.
- 원하면 할 일에 마감일을 지정할 수 있다.
- 할 일 목록의 이름이나 설명을 변경할 수 있다.
- 어떤 할 일을 ‘완료’ 혹은 ‘진행 중’으로 표시할 수 있다.
- 할 일 목록이 완료되면 보관할 수 있다.
- 완료되지 않은 할 일 목록 중 마감일이 얼마 남지 않은 일들을 모두 본다.
- ‘대기 중’ 상태인 할 일을 모두 본다.
- 할 일 목록을 보류하면서 이유를 지정한다.
- 어떤 할 일 목록의 전체 이력을 본다.
이벤트 스토밍
위 요구 사항에서 정의한 사용자 스토리를 토대로 이벤트 스토밍을 진행해보자.
이벤트 스토밍이란, 구축하려는 새로운 프로젝트에 대한 아이디어를 수집하고, 공유하여, 복잡한 비즈니스 도메인을 공동으로 탐색할 수 있는 유연한 워크숍 형식이다. - EventStorming
복잡한 문제에 마주쳤을 때, 여러 명이서 빈 벽 앞에 서서 특정 주제에 대해 각자의 생각을 포스트잇에 적어 붙여가며, 생각을 공유하면서 방향을 잡는다. 그런 다음 연관된 메모들을 모아 그룹화하고, 다른 색의 포스트잇으로 각 이벤트의 원인이 되는 행동을 적어보면, 자연스럽게 사용자 스토리가 그려지게 된다.
테스트가 개발을 안내하게 하라
TDD(테스트 주도 개발)의 저자 켄트 백은 구현을 작성하기 전에 테스트를 작성하라는 아이디어를 책에서 처음 소개했다. TDD는 실패 테스트 -> 성공 테스트 -> 리팩터링 과정을 순환하기 때문에, 빨강-초록-리팩터링 사이클이라고도 불린다.
TDD의 주요 이점은 성공 기준(success criteria)을 꼭 정의하게 만드는 것이다. 즉, 우리가 개발을 하면서 길을 잃지 않을 수 있게 되는 것이다. 특정 문제를 해결하기 전에, 문제의 해법이 어떤 형태여야 하는지를 꼭 생각하게 만든다.
지속 가능한 페이스로 생각하기
테스트 없이 비즈니스 로직 코드를 작성할 경우, 길을 잃는 경우가 많다. 그 이유는 대부분, 내가 해야할 것들이 머리 속에서 제대로 정리가 되지 않은 상태로 코드를 작성하기 때문이다. TDD를 사용하면, 지속 가능한 페이스로 생각할 수 있으며, 모든 것들을 머릿속에 기억할 필요가 없어진다.
올바름 보장하기
테스트는 자동으로 실행되고, 상대적으로 더 빠르기 때문에, TDD로 작성한 시스템은, 버그를 더 빨리 수정할 수 있다. 테스트가 존재하지 않는 시스템보다, 우리의 바램대로 작동한다는 확신을 가질 수 있다.
여러 가지 유형의 테스트
단위 테스트(Unit test)
- 효과적으로 테스트할 수 있는 가장 작은 단위에 대한 테스트
- 빠르게 실행되어야 하고, 외부 시스템과 상호작용해서는 안 된다.
- 단위 : 클래스, 메소드, 순수 함수 또는 서로 밀접하게 연관된 함수들
통합 테스트(Integration test)
- 다른 시스템과 통합하기 위한 테스트
- 애플리케이션 - 데이터베이스와 같이 분리된 두 부분이 제대로 통합되었는지 검사하기 위함
인수 테스트(Acceptance test)
- 스토리의 인수 조건을 잡아내는 테스트
- 전체 애플리케이션을 처음부터 끝까지 완전히 테스트를 진행
- 특정 스토리나 시나리오가 예상대로 작동하는지 검증
- 시스템과 사용자의 상호작용을 시뮬레이션함
단위 테스트를 함수형으로 만들기
단위 테스트를 작성할 때, 가장 흔히 사용하는 방법은 given-when-then인 전제-상황-결과이다. 함수형 프로그래밍에서도 동일하게 적용할 수 있다. 앞으로 만들 이상적인 테스트는, 메소드 체이닝에 초점을 맞추고, 함수나 함수의 체이닝이 예상대로 작동하는지를 검사할 수 있어야 한다.
위 내용을 테스트할 수 있는 방법은 2가지가 있다.
예제에 의한 테스트(test by example)
- A의 인스턴스와 그에 대해 예상되는 B의 집합을 연관시킨 일련의 예제를 제공한다.
- 각각의 A에 대해 함수(또는 함수의 연쇄)를 실행한다.
- 그 결과가 예상되는 결과에 있는 B와 같은지 검증
속성 기반 테스트(property based testing)
- 모든 가능한 A -> B 변환에 대해 성립해야만 하는 특정 속성을 정의
- 임의로 선택한 A 타입의 값들에 대해 함수를 실행
- 만들어진 모든 결과에 대해 앞에서 정한 속성이 성립하는지 검증
첫 번째 단위 테스트
@Test
fun `add two numbers`() {
expectThat(5 + 6).isEqualTo(11)
expectThat(7 + 42).isEqualTo(49)
expectThat(9999 + 1).isEqualTo(10_000)
}
이러한 테스트는, 얼마나 많은 테스트를 작성해야지 올바르게 동작한다고 할 수 있을까? 가능한 모든 덧셈을 이런 접근 방식으로는 진행하기 어려울 것이다. 대신 우리는, 무작위 값을 입력 받아 덧셈 연산의 속성을 테스트하는 것이다.
private fun randomNatural() = Random.nextInt(from = 1, until = 1000_000_000)
@Test
fun `zero identity`() {
repeat(100) {
val x = randomNatural()
expectThat(x + 0).isEqualTo(x)
}
}
@Test
fun `commutative property`() {
repeat(100) {
val x = randomNatural()
val y = randomNatural()
expectThat(x + y).isEqualTo(x + y)
}
}
@Test
fun `associative property`() {
repeat(100) {
val x = randomNatural()
val y = randomNatural()
val z = randomNatural()
expectThat((x + y) + z).isEqualTo(x + (y + z))
expectThat((y + z) + x).isEqualTo(y + (z + x))
expectThat((z + x) + y).isEqualTo(z + (x + y))
}
}
위 코드만 봐도, 함수의 속성을 테스트하는 방식이 예제 데이터 집합을 사용해 테스트 하는 방식과 어떻게 다른지 알 수 있다.
댓글남기기